#pragma once
#include "oatpp/parser/json/mapping/ObjectMapper.hpp"
#include "oatpp/web/server/api/ApiController.hpp"
#include "oatpp/web/mime/multipart/Multipart.hpp"
#include "oatpp/core/macro/codegen.hpp"
#include "../dto/SimpleDto.h"
#include "../dto/CountDto.h"
#include "../dto/ModelDto.h"
#include "../dto/ModelListDto.h"
#include "../service/ModelService.h"
#include "../util/TextUtil.h"
#include "../util/SystemHelper.h"
#include "../AiBox.h"

#include OATPP_CODEGEN_BEGIN(ApiController)

/**
 * 模型控制器
 */
class ModelController : public oatpp::web::server::api::ApiController {
public:
	ModelController(const std::shared_ptr<ObjectMapper>& objectMapper)
		: oatpp::web::server::api::ApiController(objectMapper)
	{}

	/*
	* 模型添加
	*/
	ENDPOINT("POST", "/model/add", addModel,
		HEADER(String, authorization, "Authorization"),
		BODY_DTO(Object<ModelVo>, vo)) {

		// 返回操作结果
		auto result = SimpleDto::createShared();
		result->error = -1;
		result->description = "服务器内部错误!";

		// 查找用户信息
		if (SystemConfig::get_mutable_instance().GetBoxConf().GetUser().GetToken() !=
			TextUtil::get_mutable_instance().GetToken(authorization.getValue("")))
		{
			result->description = "无效令牌!";
			return createDtoResponse(Status::CODE_200, result);
		}

		// 获取模型信息
		ModelInfo model;
		model.SetId(TextUtil::get_mutable_instance().GetGuid());
		model.SetName(vo->name.getValue(""));
		model.SetDescription(vo->description.getValue(""));
		model.SetPath(vo->path.getValue(""));
		model.SetCls(vo->cls.getValue(""));
		model.SetAlarm(vo->alarm.getValue(""));
		model.SetNormal(vo->normal.getValue(""));
		model.SetWidth(vo->width.getValue(640));
		model.SetHeight(vo->height.getValue(640));
		model.SetEnabled(vo->enabled.getValue(1));

		// 获取文件路径
		std::string name = vo->path.getValue("");
		int pos = name.find("?name=");
		if (pos == -1)
		{
			result->description = "无效模型文件!";
			return createDtoResponse(Status::CODE_200, result);
		}
		name = name.substr(pos + strlen("?name="));
		std::string path = FileUtil::GetAppPath("file/" + name);
		if (!FileUtil::Exists(path))
		{
			result->description = "模型文件不存在!";
			return createDtoResponse(Status::CODE_200, result);
		}

		// 模型id与文件id保持一致
		pos = name.rfind(".");
		if (pos != -1)
		{
			std::string id = name.substr(0, pos);
			model.SetId(id);
		}

		// 参数校验
		if (model.GetName().empty() || model.GetDescription().empty() ||
			model.GetPath().empty() || model.GetCls().empty() ||
			model.GetNormal().empty() || model.GetAlarm().empty())
		{
			result->description = "请填写模型参数!";
			return createDtoResponse(Status::CODE_200, result);
		}

		// 新增模型信息
		ModelService modelService;
		modelService.Add(model);

		// 返回操作结果
		result->error = 0;
		result->description = "success";
		result->value = model.GetId();
		return createDtoResponse(Status::CODE_200, result);
	}

	/*
	* 模型更新
	*/
	ENDPOINT("PUT", "/model/update", updateModel,
		HEADER(String, authorization, "Authorization"),
		BODY_DTO(Object<ModelVo>, vo)) {

		// 返回操作结果
		auto result = SimpleDto::createShared();
		result->error = -1;
		result->description = "服务器内部错误!";

		// 查找用户信息
		if (SystemConfig::get_mutable_instance().GetBoxConf().GetUser().GetToken() !=
			TextUtil::get_mutable_instance().GetToken(authorization.getValue("")))
		{
			result->description = "无效令牌!";
			return createDtoResponse(Status::CODE_200, result);
		}

		// 获取模型信息
		ModelInfo model;
		model.SetId(vo->id.getValue(""));
		model.SetName(vo->name.getValue(""));
		model.SetDescription(vo->description.getValue(""));
		model.SetPath(vo->path.getValue(""));
		model.SetCls(vo->cls.getValue(""));
		model.SetAlarm(vo->alarm.getValue(""));
		model.SetNormal(vo->normal.getValue(""));
		model.SetWidth(vo->width.getValue(640));
		model.SetHeight(vo->height.getValue(640));
		model.SetEnabled(vo->enabled.getValue(1));

		// 参数校验
		if (model.GetId().empty() || model.GetName().empty() ||
			model.GetDescription().empty() ||
			model.GetCls().empty() || model.GetNormal().empty() ||
			model.GetAlarm().empty())
		{
			result->description = "请填写模型参数!";
			return createDtoResponse(Status::CODE_200, result);
		}

		// 更新模型
		ModelService modelService;
		if (!modelService.Update(model))
		{
			result->description = "更新模型参数失败!";
			return createDtoResponse(Status::CODE_200, result);
		}

		// 返回操作结果
		result->error = 0;
		result->description = "success";
		return createDtoResponse(Status::CODE_200, result);
	}

	/*
	* 启用禁用模型
	*/
	ENDPOINT("GET", "/model/enable", enableModel,
		HEADER(String, authorization, "Authorization"),
		QUERY(String, id),
		QUERY(Int32, enabled)) {

		// 返回操作结果
		auto result = SimpleDto::createShared();
		result->error = -1;
		result->description = "服务器内部错误!";

		// 查找用户信息
		if (SystemConfig::get_mutable_instance().GetBoxConf().GetUser().GetToken() !=
			TextUtil::get_mutable_instance().GetToken(authorization.getValue("")))
		{
			result->description = "无效令牌!";
			return createDtoResponse(Status::CODE_200, result);
		}

		// 模型信息
		ModelInfo model;
		model.SetId(id.getValue(""));

		// 新增模型信息
		ModelService modelService;
		if (!modelService.Find(model))
		{
			result->description = "模型编码无效!";
			return createDtoResponse(Status::CODE_200, result);
		}

		// 启用禁用
		model.SetEnabled(enabled.getValue(1));
		modelService.Update(model);

		// 返回操作结果
		result->error = 0;
		result->description = "success";
		result->value = model.GetId();
		return createDtoResponse(Status::CODE_200, result);
	}

	/*
	* 删除模型
	*/
	ENDPOINT("DELETE", "/model/delete", deleteModel,
		HEADER(String, authorization, "Authorization"),
		QUERY(String, id)) {

		// 返回操作结果
		auto result = SimpleDto::createShared();
		result->error = -1;
		result->description = "服务器内部错误!";

		// 查找用户信息
		if (SystemConfig::get_mutable_instance().GetBoxConf().GetUser().GetToken() !=
			TextUtil::get_mutable_instance().GetToken(authorization.getValue("")))
		{
			result->description = "无效令牌!";
			return createDtoResponse(Status::CODE_200, result);
		}

		// 模型信息
		ModelInfo model;
		model.SetId(id.getValue(""));

		// 从model文件夹查找
		std::string path = SystemHelper::get_mutable_instance().GetFileSavePath(model.GetId() + ".onnx");
		Box::get_mutable_instance().GetFileClear()->AddFile(path);

		// 删除模型
		ModelService modelService;
		modelService.Delete(model);

		// 返回操作结果
		result->error = 0;
		result->description = "success";
		result->value = model.GetId();
		return createDtoResponse(Status::CODE_200, result);
	}

	/*
	* 获取模型数量
	*/
	ENDPOINT("GET", "/model/count", getModelCount,
		HEADER(String, authorization, "Authorization"),
		REQUEST(std::shared_ptr<IncomingRequest>, request)) {

		// 获取筛选参数
		std::string name = request->getQueryParameter("name").getValue("");
		std::string enabled = request->getQueryParameter("enabled").getValue("");
		name = TextUtil::get_mutable_instance().UrlDecode(name.c_str());

		// 返回操作结果
		auto result = CountDto::createShared();
		result->error = -1;
		result->description = "服务器内部错误!";

		// 查找用户信息
		if (SystemConfig::get_mutable_instance().GetBoxConf().GetUser().GetToken() !=
			TextUtil::get_mutable_instance().GetToken(authorization.getValue("")))
		{
			result->description = "无效令牌!";
			return createDtoResponse(Status::CODE_200, result);
		}

		// 查询模型数量
		ModelService modelService;
		int count = modelService.Count(name, enabled);

		// 返回操作结果
		result->error = 0;
		result->description = "success";
		result->value = count;
		return createDtoResponse(Status::CODE_200, result);
	}

	/**
	 * 查询模型列表
	 */
	ENDPOINT("GET", "/model/list", listModel,
		HEADER(String, authorization, "Authorization"),
		QUERY(Int32, pageIndex),
		QUERY(Int32, pageSize),
		REQUEST(std::shared_ptr<IncomingRequest>, request)) {

		// 获取筛选参数
		std::string name = request->getQueryParameter("name").getValue("");
		std::string enabled = request->getQueryParameter("enabled").getValue("");
		name = TextUtil::get_mutable_instance().UrlDecode(name.c_str());

		// 返回操作结果
		auto result = ModelListDto::createShared();
		result->error = -1;
		result->description = "服务器内部错误!";

		// 查找用户信息
		if (SystemConfig::get_mutable_instance().GetBoxConf().GetUser().GetToken() !=
			TextUtil::get_mutable_instance().GetToken(authorization.getValue("")))
		{
			result->description = "无效令牌!";
			return createDtoResponse(Status::CODE_200, result);
		}

		// 查询模型信息
		int index = (pageIndex.getValue(1) - 1) * pageSize.getValue(10);
		int size = pageSize.getValue(10);

		std::vector<ModelInfo> models;
		ModelService modelService;
		modelService.FindPage(index, size, name, enabled, models);

		// 初始化空列表
		oatpp::List<oatpp::Object<ModelVo>> items({});

		// 填充模型列表
		for (size_t index = 0; index < models.size(); ++index)
		{
			auto model = ModelVo::createShared();
			model->id = models[index].GetId();
			model->name = models[index].GetName();
			model->description = models[index].GetDescription();
			model->path = models[index].GetPath();
			model->cls = models[index].GetCls();
			model->alarm = models[index].GetAlarm();
			model->normal = models[index].GetNormal();
			model->width = models[index].GetWidth();
			model->height = models[index].GetHeight();
			model->enabled = models[index].GetEnabled();
			model->createTime = models[index].GetCreateTime().ToNormalString();
			items->emplace(items->end(), model);
		}

		// 返回模型列表
		result->error = 0;
		result->description = "success";
		result->value = items;
		return createDtoResponse(Status::CODE_200, result);
	}

	/*
	* 动态载入模型
	*/
	ENDPOINT("GET", "/model/load", loadModel,
		HEADER(String, authorization, "Authorization"),
		QUERY(String, id)) {

		// 返回操作结果
		auto result = SimpleDto::createShared();
		result->error = -1;
		result->description = "服务器内部错误!";

		// 查找用户信息
		if (SystemConfig::get_mutable_instance().GetBoxConf().GetUser().GetToken() !=
			TextUtil::get_mutable_instance().GetToken(authorization.getValue("")))
		{
			result->description = "无效令牌!";
			return createDtoResponse(Status::CODE_200, result);
		}

		// 载入模型
		EnginePtr engine = Box::get_mutable_instance().GetEngine();
		if (!engine || !engine->LoadModel(id.getValue("")))
		{
			result->description = "载入模型失败!";
			return createDtoResponse(Status::CODE_200, result);
		}

		// 返回操作结果
		result->error = 0;
		result->description = "success";
		return createDtoResponse(Status::CODE_200, result);
	}
};

#include OATPP_CODEGEN_END(ApiController)